<?php

namespace App\Http\Controllers\Backend;

use App\Http\Controllers\Controller;
use App\Jobs\TaskJob;
use App\Models\Admin;
use App\Models\ArticleCollect;
use App\Models\ArticleComment;
use App\Models\Dispatch;
use App\Models\Event;
use App\Models\FangtanUser;
use App\Models\Fresh;
use App\Models\FreshTopic;
use App\Models\FreshUser;
use App\Models\FreshVoice;
use App\Models\Need;
use App\Models\News;
use App\Models\NewsDesc;
use App\Models\SiteGold;
use App\Models\SiteType;
use App\Models\User;
use App\Models\UserGold;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Cache;

class BaseController extends Controller
{
    protected $model;
    protected $error;
    protected $myUser;

    // 初始化
    public function initialize()
    {
        // 获取用户信息
        $user = $this->myUser();

        // 权限判断 通过控制器来判断
        $controller   = strtolower($this->controller);
        $this->myUser = $user;


        // 所有的人都可以操作的控制器：测试，登录，
        if(!in_array($controller, ['account', 'test', 'frontend', 'deal'])){
            $this->throwIf(empty($user), '请登录后在操作！！', LOGIN_ERROR);

            // TODO 公共权限
            //   发布文章快讯新鲜事：可以选择用户，选择话题
            $con_act = $controller.'_'.$this->action;
            $hasRole = in_array($con_act, ['user_lists', 'topic_lists',]);

            // 判断权限：是否含有当前控制器 => 如果不存在 则没有权限
            // 如果是1 超级管理员 所有权限都有
            if(($user['uid'] != 1) || empty($hasRole)){
                // 权限处理
                /*// $role = $user['role'] ?? '[]';
                // $role = json_decode($role, true);
                $role = array_column($user['role'], 'role');

                // 其中几个特殊控制器
                $all         = [];
                $controllers = ['point', 'business', 'dispatch', 'abroad', 'news', 'author', 'image',];
                foreach($user['role'] as $item){
                    $_role = $item['role'];
                    if(in_array($_role, $controllers)){
                        $all[] = $_role.'-cate';
                        $all[] = $_role.'-article';
                        $all[] = 'comment';
                    }
                    // 栏目中，获取文章列表
                    if($_role == 'cate'){
                        $all[] = 'article';
                    }
                    $all[] = $_role;
                }

                $this->throwIf(!in_array($controller, $all), '你没有该操作权限！！');*/
            }
            /*if($user['uid'] == 1){
                $this->throwIf(!$user['hasRole'], '你没有该操作权限！！');
            }*/

        }
    }

    // 获取用户以及权限
    protected function myUser()
    {
        $token = $this->request->header('token');
        if(empty($token)){
            return [];
        }

        // TODO 为了避免解析以前的token报错（The payload is invalid.）
        try{
            $user = Crypt::decryptString($token);
            $user = json_decode($user, true);
        } catch(\Exception $e){
            $user = [];
        }
        $this->throwIf(empty($user), 'token过期，请重新登录！！', LOGIN_ERROR);

        $admin = new Admin();
        $info  = $admin->isCache(true)->oneFind(['id' => $user['id']]); // ->recycle()
        $this->throwIf(empty($info), '登录过期，请重新登录！！', LOGIN_ERROR);
        //$this->throwIf(empty($info), '用户不存在！！');
        if($user['id'] != 1){
            $this->throwIf($info->status === 0, '用户被禁用！！', LOGIN_ERROR);
        }
        // 组合
        $info->uid = $info->id;
        $hasRole   = true;

        //makeRoles($roles, $is_parent = true);
        // 判断权限
        /*if($info->uid != 1){
            $roles      = $info->getRawOriginal('role');
            $roles      = is_string($roles) ? json_decode($roles) : $roles;
            $controller = strtolower($this->controller);
            $action     = strtolower($this->action);
            $cate_id    = $this->getData('cate_id', 0, 'intval');    // 一些栏目权限
            // TODO 权限判断1、根据操作控制器来判断
            // TODO 权限判断2、文章列表，根据控制与栏目id判断
            // TODO 权限判断3、两个特殊栏目：草稿与头条的文章列表，根据控制与操作方法header和draft来判断
            $param = $cate_id;
            if(in_array($action, ['header', 'draft'])){
                $param = $action;
            }

            $hasRole = $admin->checkRole($roles, $controller, $param);
        }
        // 重新组合
        $info->hasRole = $hasRole;*/

        return $info->toArray();
    }

    ###############################################################################################
    ## 数据操作
    ###############################################################################################

    // 返回列表数据
    public function lists()
    {
        $where = $this->listWhere();
        $page  = $this->page;
        $rows  = $this->rows;
        $model = $this->checkModel($this->model);
        if($model === false){
            return $this->error($this->error);
        }

        // 模型 和 查询
        if($where){
            $result = $model->listPage($where, $page, $rows, "id DESC");
        } else{
            $result = $model->isCache(true)->listPage($where, $page, $rows, "id DESC");
        }

        return $this->success($result);
    }

    // 删除
    public function del()
    {
        $this->throwIf(empty($this->id), '请指定删除记录');

        $where  = ['id' => $this->id];
        $model  = $this->checkModel($this->model);
        $result = $model->isCache(true)->oneDelete($where);
        $this->throwIf($result === false, $model->getError());

        return $this->success();
    }

    // 查找
    public function show()
    {
        $this->throwIf(empty($this->id), '请指定查看记录');

        $where = ['id' => $this->id];
        $model = $this->checkModel($this->model);
        $info  = $model->isCache(true)->oneFind($where);
        $this->throwIf($info === false, $model->getError());

        return $this->success($info);
    }

    // 改变（直接修改，软删除，改变状态，排序）
    public function edit()
    {
        $this->throwIf(empty($this->id), '请指定修改的ID编号！');
        $data = $this->_before_edit();
        $this->throwIf($data === false, $this->error);

        // 组合数据
        $where = $this->editWhere();
        $data  = $this->filterNull($data);
        $model = $this->checkModel($this->model);
        $data  = $model->checkData($data, $where);
        $this->throwIf($data === false, $model->getError());

        // 验证
        $result = $model->checkRules($data, 'edit');
        $this->throwIf($result === false, $model->getError());


        $result = $model->oneEdit($where, $data);
        $this->throwIf($result === false, $model->getError());

        return $this->success();
    }

    // 树状
    public function add()
    {
        $data = $this->_before_add();
        $this->throwIf($data === false, $this->error);

        // 组合数据
        $data  = $this->filterNull($data);
        $model = $this->checkModel($this->model);
        $data  = $model->checkData($data);
        $this->throwIf($data === false, $model->getError());

        // 验证
        $result = $model->checkRules($data, 'add');
        $this->throwIf($result === false, $model->getError());

        // 保存
        $result = $model->oneAdd($data);
        $this->throwIf($result === false, $model->getError());

        return $this->success();
    }

    // 列表条件
    protected function listWhere() { return []; }

    // 列表 条件
    /*protected function listWhere()
    {
        $model = $this->checkModel($this->model);

        return $model->queryWhere();
    }*/

    protected function editWhere() { return ['id' => $this->id]; }

    protected function showWhere() { return ['id' => $this->id]; }

    protected function delWhere() { return ['id' => $this->id]; }

    // ajax改变某个字段的值
    protected function changeField($_field, $_value)
    {
        $id = $this->id;
        if(empty($id) || empty($_field) || ($_value === '')){
            return $this->error('请指定修改参数！！');
        }

        // 执行
        $deal   = $this->checkModel($this->model);
        $result = $deal->oneEdit(['id' => $id], [$_field => $_value]);
        $this->throwIf($result === false, $deal->getError());

        return $this->success([], '更新成功！');
    }



    ###############################################################################################
    ## 树状数据+缓存 操作
    ###############################################################################################
    // 得到树状数据id 用于计算包含有他子级的数据信息
    protected function tree_child_id($model, $myid = 0, $where = [], $instantiation = false)
    {
        // 返回数据，不包含自己
        $list = $this->tree_list($model, $myid, $where, $instantiation);
        if(empty($list)){
            return [$myid];
        }

        // 重新取值
        $ids = array_column($list, 'id');
        if(empty($ids)){
            $ids = [$myid];
        }

        return $ids;
    }

    // 得到树状数据id 用于计算包含有他父级的数据信息
    protected function tree_parent_id($model, $myid = 0, $where = [], $instantiation = false)
    {
        $list = $this->tree_parent($model, $myid, $where, $instantiation);

        $ids = array_column($list, 'id');
        if(empty($ids)){
            $ids = [$myid];
        }

        return $ids;
    }

    // 生成树状 并缓存
    protected function tree_make($myid = 0, $where = [])
    {
        // 读取缓存文件 直接返回
        $model    = $this->model;
        $cacheKey = $model.'_tree_make_'.$myid.var_export($where, 1);
        if(Cache::has($cacheKey)){
            return Cache::get($cacheKey);
        }

        // 如果模型没有被实例化 检查模型是否存在
        $model = $this->checkModel($model);

        // 查询
        if($where){
            $db_list = $model::where($where)->recycle()->get()->toArray();
        } else{
            $db_list = $model::recycle()->get()->toArray();
        }

        // 生成树状
        $tree = new Tree();
        $tree->init($db_list);
        $list = $tree->toTree($db_list, $myid);

        // 测试
        //$list = $tree->get_tree($myid);  // 可用
        //$list = $tree->get_list($myid);  // 可用
        //$list = $tree->get_all_child_id($myid);  // 可用
        //$list = $tree->toTree($db_list, $myid); // 可用
        //$list = $tree->toList($db_list, $myid); // 可用
        //$list = $tree->getAllChildId($db_list, $myid); // 可用

        // 缓存起来 下次直接返回
        Cache::put($cacheKey, $list);
        (new $model)->cacheFile($cacheKey);

        return $list;
    }

    // 生成树状 并缓存
    protected function tree_list($myid = 0, $where = [])
    {
        // 读取缓存文件 直接返回
        $model    = $this->model;
        $cacheKey = $model.'_tree_list_'.$myid.var_export($where, 1);
        if(Cache::has($cacheKey)){
            return Cache::get($cacheKey);
        }

        // 如果模型没有被实例化 检查模型是否存在
        $model = $this->checkModel($model);


        // 查询
        if($where){
            $db_list = $model::where($where)->recycle()->get()->toArray();
        } else{
            $db_list = $model::recycle()->get()->toArray();
        }

        // 生成树状列表
        $tree = new Tree();
        $tree->init($db_list);
        $list = $tree->toList($db_list, $myid); // 返回数据，不包含自己这条数据

        // 缓存起来 下次直接返回
        Cache::put($cacheKey, $list);
        (new $model)->cacheFile($cacheKey);

        return $list;
    }

    // 树状
    protected function tree_parent($myid = 0, $where = [])
    {
        // 读取缓存文件 直接返回
        $model    = $this->model;
        $cacheKey = $model.'_tree_parent_'.$myid.var_export($where, 1);
        if(Cache::has($cacheKey)){
            return Cache::get($cacheKey);
        }

        // 检查模型是否存在
        // 如果模型没有被实例化 检查模型是否存在
        $model = $this->checkModel($model);

        // 查询
        if($where){
            $db_list = $model::where($where)->recycle()->get()->toArray();
        } else{
            $db_list = $model::recycle()->get()->toArray();
        }

        // 生成树状列表
        $tree = new Tree();
        $tree->init($db_list);
        $list = $tree->getAllParent($myid, $db_list);

        // 缓存起来 下次直接返回
        Cache::put($cacheKey, $list);
        (new $model)->cacheFile($cacheKey);

        return $list;
    }

    ###############################################################################################
    ## before 操作
    ###############################################################################################


    // 获取认证类型
    protected function userType()
    {
        $where  = [['channel', 'in', ['user_type', 'organ_type']]];
        $where1 = ['channel' => 'user_type'];
        $where2 = ['channel' => 'organ_type'];
        $where3 = ['channel' => 'user_medium'];
        $where4 = ['channel' => 'user_expert'];
        $typeDb = new SiteType();
        $lists1 = $typeDb->isCache(true)->getAll($where1);
        $lists2 = $typeDb->isCache(true)->getAll($where2);
        $lists3 = $typeDb->isCache(true)->getAll($where3);
        $lists4 = $typeDb->isCache(true)->getAll($where4);
        $lists  = array_merge($lists1, $lists2, $lists3, $lists4);
        $lists  = array_column($lists, null, 'id');

        return $lists;
    }

    // 队列消息：添加积分
    protected function addGold($field, $uid)
    {
        if(empty($uid)){
            return true;
        }

        $goldDb = new SiteGold();
        // 获取任务信息
        $taskInfo = $goldDb->isCache(true)->oneFind(['field' => $field]);
        if(empty($taskInfo)){
            return true;
        }


        $uGoldDb = new UserGold();
        $result  = $uGoldDb->isFinish($taskInfo, $uid);
        if($result){
            return true;
        }

        // 发送任务
        //TaskJob::dispatchIf(true, $data)->onQueue('member_task');
        $data = ['uid' => $uid, 'field' => $field];
        $res  = TaskJob::dispatch($data)->onQueue('member_task');

        return $res;
    }

    // 整理结果（App中需要判断登录用户是否管理，后台不需要，所以不放在主控制器中）
    protected function makeFreshListResult($lists, $fangtan_id = 0, $reAte = false)
    {
        if(empty($lists)){
            return $lists;
        }

        // 模型
        $fuDb      = new FreshUser();
        $ftDb      = new FreshTopic();
        $fvDb      = new FreshVoice();
        $collectDb = new ArticleCollect();
        $nDescDb   = new NewsDesc();
        $needDb    = new Need();
        $eventDb   = new Event();
        $newsDb    = new News();
        $dispDb    = new Dispatch();
        $acDb      = new ArticleComment();
        $userDb    = new User();
        $freshDb   = new Fresh();
        $ufield    = $this->userField();

        // 快讯
        $dids   = array_column($lists, 'dispatch_id');
        $dids   = array_diff($dids, [0]);
        $dlists = $dispDb->isCache(true)->getListInIds($dids);

        // 新闻
        $nids = array_column($lists, 'news_id');
        $nids = array_diff($nids, [0]);
        $news = $newsDb->isCache(true)->getListInIds($nids);

        // 需求
        $edids = array_column($lists, 'need_id');
        $edids = array_diff($edids, [0]);
        $needs = $needDb->isCache(true)->getListInIds($edids);

        // 活动
        $evids  = array_column($lists, 'event_id');
        $evids  = array_diff($evids, [0]);
        $events = $eventDb->isCache(true)->getListInIds($evids);

        // 父级
        $pids   = array_column($lists, 'parent_id');
        $pids   = array_diff($pids, [0]);
        $plists = $freshDb->isCache(true)->getListInIds($pids);

        // 用户
        $uids  = array_column($lists, 'uid');
        $users = $userDb->isCache(true)->getListInIds($uids, $ufield);
        $types = $this->userType(); // 认证类型

        // 如果是访谈
        if($fangtan_id){
            $fUserDb   = new FangtanUser();
            $fusers    = $fUserDb->isCache(true)->getList(['fangtan_id' => $fangtan_id, 'status' => 1]);
            $fusers    = is_object($fusers) ? $fusers->toArray() : $fusers;
            $userTypes = ['guest' => '嘉宾', 'host' => '主持人',];
            $fmember   = [];
            foreach($fusers as $_user){
                $_uid = $_user['uid'];
                //组合
                if($_user['itype'] == 'host'){
                    $fmember[$_uid] = $_user;
                } elseif($_user['itype'] == 'guest'){
                    $fmember[$_uid] = $_user;
                }
            }
        }

        // 整理
        foreach($lists as $key => $item){
            $_did     = $item['dispatch_id'];
            $_nid     = $item['news_id'];
            $_pid     = $item['parent_id'];
            $_enid    = $item['need_id'];
            $_evid    = $item['event_id'];
            $_ftid    = $item['fangtan_id'];
            $_uid     = $item['uid'];
            $_freshId = $item['id'];

            // 如果是转发的 获取原文
            $prow = $plists[$_pid] ?? [];
            if($prow){
                $prow['channel'] = 'fresh';
                if(!empty($prow["content"])){
                    $prow["images"]  = $this->makeFullFile($prow['images']);  // 图片;
                    $prow["content"] = $this->makeResult4Content($prow["content"], $_pid);
                }
                $prow['user'] = $this->getUserInfo($prow['uid']);
            } else{
                $prow = (object)[];
            }
            // 如果是文章
            $nrow = $news[$_nid] ?? [];
            if($nrow){
                $nrow['channel'] = 'news';
                $nrow['user']    = $this->getUserInfo($nrow['uid']);
            } else{
                $nrow = (object)[];
            }
            // 如果是需求
            $enrow = $needs[$_enid] ?? [];
            if($enrow){
                $enrow['channel'] = 'need';
                $enrow['user']    = $this->getUserInfo($enrow['uid']);
                //$enrow["content"] = $this->makeListShow($enrow["content"], 'news');
                $enrow["images"]  = $this->getThumbFiles($enrow['images']);  // 图片;
                //$enrow["images"]  = $this->makeFullFile($enrow['images'], 690);  // 图片;
                // 父级
                $parent = $enrow;
            }
            // 如果是活动
            $evrow = $events[$_evid] ?? [];
            if($evrow){
                $evrow['channel'] = 'event';
                $evrow['user']    = $this->getUserInfo($evrow['uid']);
                //$evrow["content"] = $this->makeListShow($desc_coontent, 'news');
                //$evrow["images"]  = $this->getThumbFiles($evrow['images']);  // 图片;
                //$evrow["images"]  = $this->makeFullFile($evrow['images'], 690);  // 图片;
                // 父级
                $parent = $evrow;
            }
            // 快讯
            $drow = $dlists[$_did] ?? [];
            if($drow){
                $drow['channel'] = 'dispatch';
                $drow['user']    = $this->getUserInfo($drow['uid']);
            } else{
                $drow = (object)[];
            }

            // 获取一条评论
            $where   = ['channel' => 'fresh', 'verify' => '1', 'pid' => '0', 'article_id' => $_freshId];
            $comment = $acDb->isCache(true)->getList($where, 1);
            $comment = is_object($comment) ? $comment->toArray() : $comment;
            if($comment){
                $comment = $comment[0];
                // 组合用户信息
                $comment['user']    = $this->getUserInfo($comment['uid']);
                $comment['content'] = $this->makeResult4Content($comment['content']);
            }

            // 用户信息
            $urow = $users[$_uid] ?? [];
            if($urow){
                $urow["head_img"]   = $this->getHeadImg($urow["head_img"]);
                $urow['apply_type'] = $urow['is_apply'] == 1 ? ($types[$urow['apply_type']]['name'] ?? '') : '';
                if(!empty($fmember[$_uid])){
                    $urow['member_type'] = $userTypes[$fmember[$_uid]['itype']] ?? '';
                } else{
                    $urow['member_type'] = '';
                }
            }

            // 整理内容(列表需要去除图片)
            $content = $this->makeResult4Content($item["content"], $_freshId);
            $content = $this->makeListShow($content);

            // 如果是语音
            if($item['number'] > 0){
                $lists[$key]['voice'] = $fvDb->isCache(true)->getOneById($_freshId, ['*'], 'fresh_id');
            }

            // 组合一下
            $lists[$key]['to_uid']  = $item['to_uid'] ? json_decode($item['to_uid']) : $item['to_uid'];
            $lists[$key]['user']    = $urow;
            $lists[$key]['images']  = $this->makeFullFile($item['images']);  // 图片
            $lists[$key]['comment'] = $comment ? $comment : (object)[];
            $lists[$key]['channel'] = 'fresh';
            $lists[$key]['content'] = $content;
            $lists[$key]['parent']  = $prow ?: ($nrow ?: $drow);
        }

        return $lists;
    }

    ###############################################################################################
    ## before 操作
    ###############################################################################################

    // 添加之前
    protected function _before_add()
    {
        return $this->data;
    }

    // 修改之前
    protected function _before_edit()
    {
        return $this->data;
    }

    // 修改之前
    protected function _before_change()
    {
        return true;
    }

    // 删除之前
    protected function _before_del()
    {
        return true;
    }

    // 列表之前
    protected function _before_lists()
    {
        return true;
    }

    // 查询之前
    protected function _before_show()
    {
        return true;
    }

    // 查询之前
    protected function _before_find()
    {
        return true;
    }

}


